package com.androdro.bluenote.coolstruttin1588;
/**
 * Cool Struttin'
 * BlueMinor.java
 *
 * @author Hiroaki Sakuma <sakuma@androdro.com>
 * @version $Id$
 *
 * Copyright (C) androdro lab. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of the nor the names of its contributors may be used to
 *   endorse or promote products derived from this software without specific
 *   prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 *
 */

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.net.http.AndroidHttpClient;
import android.os.Handler;
import android.text.Html;
import android.view.View;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.androdro.bluenote.coolstruttin1588.adapter.*;
import com.androdro.bluenote.coolstruttin1588.utility.Define;

public abstract class BlueMinor
	extends
		LinearLayout
	implements
		View.OnClickListener,
		Runnable {

	/**
   *
   */

	protected CoolStruttin root;
	protected String mapname;

	private Resources r;
	private LinearLayout.LayoutParams layoutparams;
	private ListView lv;
	private BlueMinorAdapter adapter;
	private Thread t;
	private Handler h;


	public BlueMinor(CoolStruttin root, String mapname) {

		super(root);
		this.root = root;
		this.mapname = mapname;

		Thread t;
		TextView tv;

		try {

			this.r = this.root.getResources();

			this.layoutparams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);


			setOrientation(LinearLayout.VERTICAL);
			setBackgroundColor(Color.WHITE);

			this.layoutparams.setMargins(0, 10, 0, 10);


			tv = new TextView(this.root);
			tv.setText(Html.fromHtml(this.r.getString(R.string.result_header, this.mapname, new Date())));
			tv.setLayoutParams(this.layoutparams);
			addView(tv);


			this.lv = new ListView(this.root);
			this.lv.setCacheColorHint(Color.WHITE);

			this.adapter = new BlueMinorAdapter(this.root);
			this.lv.setAdapter(this.adapter);

			addView(this.lv);


			tv = new TextView(this.root);
			tv.setText(Html.fromHtml(this.r.getString(R.string.result_footer)));
			tv.setOnClickListener(this);
			tv.setLayoutParams(this.layoutparams);
			addView(tv);


			h = this.root.getHandler();;
			t = new Thread(this);

			synchronized(t) {
				t.start();
				try {
					t.wait();
				} catch(InterruptedException ex) {
					ex.printStackTrace();
				}
				this.adapter.notifyDataSetChanged();
			}


		} catch (Exception e) {
			e.printStackTrace();
			Toast.makeText(this.root, e.toString() + "on " + getClass().toString() + " " + e.getStackTrace()[0].getMethodName(), Toast.LENGTH_LONG).show();
		}

	}



	public BlueMinor(CoolStruttin root) {
		this(root, "");
	}



	@Override
	protected void onDraw(Canvas canvas) {
	}


	public void run() {

		Bitmap map = null;
		List<SippinAtBells.Status> result = new ArrayList<SippinAtBells.Status>();
		AndroidHttpClient client;
		Thread t = Thread.currentThread();
		long time, last = 0;

		try {

			while(t != null && !this.root.isFinishing()) {

				synchronized(t) {

					time = System.currentTimeMillis();

					if (time > last + 150 * 1000) {
						map = null;
					}

					if (map == null) {

System.out.println("get map:" + getMapImagePath());
						HttpGet request = new HttpGet(getMapImagePath());
						client = AndroidHttpClient.newInstance(Define.URL.HTTP_USER_AGENT, this.root);
						try {

							map = client.execute(request, new ResponseHandler<Bitmap>() {
								public Bitmap handleResponse(HttpResponse response)
									throws
										ClientProtocolException,
										IOException {
											switch(response.getStatusLine().getStatusCode()) {
												case HttpStatus.SC_OK:
													return BitmapFactory.decodeStream(response.getEntity().getContent());
												default:
													return null;
											}
								}

							});

						} finally {
							client.getConnectionManager().shutdown();
							client.close();
						}

						last = time;

						result = checkMap(map);
						this.adapter.setItems(result);

						h.post(
							new Runnable() {
								public void run() {
									adapter.notifyDataSetChanged();
								}
							}
						);

					}

					t.notify();

				} //synchronized
				Thread.sleep(10000);

			} //while

			synchronized(t) {
				t.notifyAll();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}


	}


	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
			//this.holder.setFixedSize(w, h);
	}


	protected String getMapImagePath() {
		return this.root.getBackground().getHighwayImageURL(getMapName());
	}


	protected abstract String getMapKind();


	protected abstract String getMapName();


	protected List<SippinAtBells.Status> checkMap(Bitmap map) {

		JSONObject config = this.root.getConfig();
		Map<Integer, String> status = new HashMap<Integer, String>();
		List<SippinAtBells.Status> result = new ArrayList<SippinAtBells.Status>();

		try {

			JSONObject highway = this.root.getBackground().getHighway(getMapName());
			JSONObject colors = highway.getJSONObject("Colors");
			Iterator colorsi = colors.keys();
			while(colorsi.hasNext()) {
				String k = colorsi.next().toString();
				status.put(Integer.parseInt(colors.getString(k), 16), k);
			}

			JSONArray checkpoints = highway.getJSONArray("CheckPoints");
			int cl = checkpoints.length();
			for(int ci = 0; ci < cl; ci++) {

				JSONArray checkpoint = checkpoints.getJSONObject(ci).getJSONArray("Points");
				String name = checkpoints.getJSONObject(ci).getString("Name");
				String line = checkpoints.getJSONObject(ci).getString("Line");

				HashMap<String, SippinAtBells.Status> r = new HashMap<String, SippinAtBells.Status>();

				int l = checkpoint.length();
				for (int i = 0; i < l; i++) {

					int cx, cy, cx2, cy2;
					double ct;

					try {

						cx = (int)checkpoint.getJSONObject(i).getLong("x");
						cy = (int)checkpoint.getJSONObject(i).getLong("y");
						try {
							cx2 = (int)checkpoint.getJSONObject(i).getLong("x2");
							cy2 = (int)checkpoint.getJSONObject(i).getLong("y2");
						} catch (JSONException jsone) {
							cx2 = cx;
							cy2 = cy;
						}

						if (cx2 - cx != 0 && cy2 - cy != 0) {

							ct = (cy2 - cy) / (cx2 - cx);

							if (cx > cx2) {
								int tmp = cx; cx = cx2; cx2 = tmp;
								tmp = cy; cy = cy2; cy2 = tmp;
							}

							for (int xi = cx; xi <= cx2; xi++) {
								int yi = cy + (int)ct * (xi - cx);
								//System.out.println("xi=" + xi + "; yi=" + yi + "; color=x" + Integer.toHexString(map.getPixel(xi, yi) & 0x00fcfcfc) + ", " + name);

								int s = checkCondition(map.getPixel(xi, yi), status);
								switch(s) {
									case Define.CONDITION.CONDITION_CLOSED:
									case Define.CONDITION.CONDITION_ACCIDENT:
									case Define.CONDITION.CONDITION_CONGESTION:
									case Define.CONDITION.CONDITION_SNOW:
									case Define.CONDITION.CONDITION_JAM:
									case Define.CONDITION.CONDITION_OTHER:
										System.out.println(name + ": x=" + xi + ", y=" + yi + ", color=" + Integer.toHexString(map.getPixel(xi, yi)));
									default:
										r.put(getMapName() + line + name + Integer.toString(s), SippinAtBells.getInstance().getFactory().generateStatus(s, line, name));
								}

							}


						} else {

							if (cx > cx2) {
								int tmp = cx; cx = cx2; cx2 = tmp;
							}

							if (cy > cy2) {
								int tmp = cy; cy = cy2; cy2 = tmp;
							}

							//System.out.println("x=" + cx + "; y=" + cy + "; x2=" + cx + "; y2=" + cy + "; color=x" + Integer.toHexString(map.getPixel(cx, cy) & 0x00fcfcfc) + ", " + name);

							for (int xi = cx; xi <= cx2; xi++) {
								for (int yi = cy; yi <= cy2; yi++) {

									int s = checkCondition(map.getPixel(xi, yi), status);
									switch(s) {
										case Define.CONDITION.CONDITION_CLOSED:
										case Define.CONDITION.CONDITION_ACCIDENT:
										case Define.CONDITION.CONDITION_CONGESTION:
										case Define.CONDITION.CONDITION_SNOW:
										case Define.CONDITION.CONDITION_JAM:
										case Define.CONDITION.CONDITION_OTHER:
											System.out.println(name + ": x=" + xi + ", y=" + yi + ", color=" + Integer.toHexString(map.getPixel(xi, yi)));
										default:
											r.put(getMapName() + line + name + Integer.toString(s), SippinAtBells.getInstance().getFactory().generateStatus(s, line, name));
									}

								}
							}

						}

					} catch (JSONException jsone) {
					}

				} //for (points)

				for (String k2 : r.keySet()) {
					result.add(r.get(k2));
				}

			} //while(checkpointsi.hasNext())

			//System.out.println(result);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;

	}


	protected Integer checkCondition(int color, Map<Integer, String> status) {

		Integer decleasecolor = Integer.valueOf(color & 0x00fcfcfc);
		Map<Integer, String> decleasestatus = new HashMap<Integer, String>();

		for (Integer k : status.keySet()) {
			decleasestatus.put(k & 0xfcfcfc, status.get(k));
		}

		String s = decleasestatus.get(decleasecolor);

		if (s == null) {
			return 0;
		} else if (s.equals("closed")) {
			return Define.CONDITION.CONDITION_CLOSED;
		} else if (s.equals("accident")) {
			return Define.CONDITION.CONDITION_ACCIDENT;
		} else if (s.equals("congestion")) {
			return Define.CONDITION.CONDITION_CONGESTION;
		} else if (s.equals("snow")) {
			return Define.CONDITION.CONDITION_SNOW;
		} else if (s.equals("jam")) {
			return Define.CONDITION.CONDITION_JAM;
		} else if (s.equals("other")) {
			return Define.CONDITION.CONDITION_OTHER;
		} else {
			return 0;
		}

	}


		public void onClick(View v) {

			h.post(
				new Runnable() {
					public void run() {
						root.go(Define.ACTION.ACTION_INFO, getMapImagePath());
					}
				}
			);

		}

}
